package com.jiangyg.mall.core.support.snowflake;

import com.jiangyg.mall.core.support.env.EnvConstant;
import com.jiangyg.mall.core.exception.CoreException;
import com.jiangyg.mall.core.support.cache.CacheAdapter;
import com.jiangyg.mall.core.utils.Logger;
import lombok.extern.slf4j.Slf4j;

/**
 * 类描述：注意同一机房同一应用不要超过31台服务，否则可能会出现重复ID
 *
 * @author jiangyg
 * @version 4.0
 * @date 2021-10-14
 */
@Slf4j
public class SnowflakeBuilder {

    /**
     * 是否已经初始化
     */
    private volatile boolean initialized = false;

    /**
     * 雪花算法实现
     */
    private static Snowflake snowflake;

    /**
     * 单例
     */
    private static final SnowflakeBuilder builder = new SnowflakeBuilder();

    private SnowflakeBuilder() {
    }

    /**
     * 功能描述：初始化雪花算法生成器
     *
     * @param cacheAdapter 缓存，一般Redis缓存
     */
    public static synchronized SnowflakeBuilder init(CacheAdapter cacheAdapter) {
        if (builder.initialized) {
            throw new CoreException("雪花算法生成器只能初始化一次！");
        }
        // 机房ID的缓存key
        long datacenterId = builder.createDatacenterId(cacheAdapter);
        // 机器ID的缓存key
        long workId = builder.createWorkId(cacheAdapter);
        Logger.info(log, () -> String.format("初始化雪花算法生成器：生成机房ID[%d]机器ID[%d]", datacenterId, workId));
        // 初始化雪花算法对象
        snowflake = new Snowflake(workId, datacenterId, 1L);
        builder.initialized = true;
        return builder;
    }

    /**
     * 功能描述：生成随机ID
     *
     * @return 随机ID
     */
    public static Long nextId() {
        if (!builder.initialized) {
            throw new CoreException("请先初始化雪花算法生成器！");
        }
        return snowflake.nextId();
    }

    /**
     * 功能描述：生成一个机房ID，最大值31，如果超过31则从1开始
     *
     * @return 机房ID
     */
    private long createDatacenterId(CacheAdapter cacheAdapter) {
        // 获取应用的雪花计数器
        final Integer value = obtainDatacenterId(cacheAdapter);
        Logger.warn(log, () -> String.format("初始化雪花算法生成器：当前应用获取真实的机房ID[%d]", value));
        // 对31取余
        return value % 31;
    }

    /**
     * 功能描述：获取机房计数
     *
     * @param cacheAdapter 缓存
     * @return 计数
     */
    private Integer obtainDatacenterId(CacheAdapter cacheAdapter) {
        // 应用名称
        final String name = EnvConstant.getString("spring.application.name");
        // 获取应用的雪花计数器
        String cacheKey = String.format("snowflake:datacenter:%s", name);
        Integer value = cacheAdapter.get(cacheKey);
        if (value == null) {
            value = cacheAdapter.increment(cacheKey, 1L).intValue();
        }
        return value;
    }

    /**
     * 功能描述：生成一个机器ID，最大值31，如果超过31则从1开始
     *
     * @return 机器ID
     */
    private long createWorkId(CacheAdapter cacheAdapter) {
        // 应用名称
        final String name = EnvConstant.getString("spring.application.name");
        // 获取应用的雪花计数器
        final Long value = cacheAdapter.increment(String.format("snowflake:work:%s", name), 1L);
        Logger.warn(log, () -> String.format("初始化雪花算法生成器：当前应用获取真实的机器ID[%d]", value));
        // 对31取余
        return value % 31;
    }

}
